﻿using DG.Tweening;
using System.Collections.Generic;
using UnityEngine;

public class TargetSlicer : MonoSingleton<TargetSlicer> {
    public new Camera camera;
    public float minDistanceForSlicing = 80f;
    public float cooldownTime = 0.1f;

    [HideInInspector]
    public int sampleCount = 10;


    public bool IsDone {
        get; private set;
    }

    public bool IsIgnoreSlice {
        get; set;
    }

    public event System.Action onIgnoreSliceCallback;
    public event System.Action onSliceComplete;

    public void Restart() {
        IsDone = false;
        _interval = 0f;
        sampleCount = 10;
    }

    float _interval;
    float _deltaTime = 0.2f;
    Vector3 _startPos;
    float _cooldownTime;
    float _showHandTipsInterval = 8f;

    public void EnableTrail(bool isEnabled) {
        StopAllCoroutines();

        if (isEnabled) {
            CommonUtility.InstantiateFrom(ChineseRestaurantResPath.TRAIL, transform);
            StartCoroutine(TimeUtility.DelayInvoke(_showHandTipsInterval, () => LevelSecond.Instance.ShowHandTips()));
        } else {
            if (transform.childCount > 0) {
                Destroy(transform.GetChild(0).gameObject);
            }
        }
    }

    void Update() {
        if (IsDone) {
            return;
        }

        if (SlicedTarget.Targets.Count >= sampleCount) {
            IsDone = true;

            // 禁用刀光效果
            EnableTrail(false);

            AudioManager.Instance.PlaySound(ChineseRestaurantResPath.SFX_SUCCESS);
            var vfx = CommonUtility.InstantiateFrom(ChineseRestaurantResPath.VFX_SUCCESS, null);
            vfx.gameObject.AddComponent<ParticleSystemFate>();
            var center = Vector3.zero;

            foreach (var t in SlicedTarget.Targets) {
                center += t.transform.position;
            }

            center /= SlicedTarget.Targets.Count;
            vfx.position = center + (Vector3.up * 0.1f);

            StartCoroutine(TimeUtility.DelayInvoke(2f, () => {
                foreach (var t in SlicedTarget.Targets) {
                    var target = t.transform;
                    var rigidbody = target.GetComponent<Rigidbody>();
                    rigidbody.isKinematic = true;

                    StartCoroutine(TimeUtility.DelayInvoke(_interval, () => {
                        rigidbody.transform.DOLocalMove(Vector3.up * 0.5f, 0.3f).OnComplete(() => {
                            rigidbody.isKinematic = false;
                            t.AddPhysicMaterial();
                            t.RemoveSelf();

                            if (SlicedTarget.Targets.Count <= 0) {
                                Restart();

                                if (onSliceComplete != null) {
                                    onSliceComplete();
                                }
                            }
                        });
                    }));

                    _interval += _deltaTime;
                }
            }));

            return;
        }

        if (Input.GetMouseButtonDown(0)) {
            _startPos = Input.mousePosition;
            _cooldownTime = cooldownTime;
        } else if (Input.GetMouseButton(0)) {
            _cooldownTime -= Time.deltaTime;

            if (_cooldownTime < 0f) {
                OnSlice();

                if (SlicedTarget.Targets.Count > 1) {
                    LevelSecond.Instance.ShowHandTips();
                }
            }
        }
    }

    public void HideHandTips() {
        LevelSecond.Instance.ShowHandTips(true);
    }

    void OnSlice() {
        _cooldownTime = cooldownTime;
        var endPos = Input.mousePosition;
        var delta = (endPos - _startPos).magnitude;

        if (delta < minDistanceForSlicing) {
            return;
        }

        if (IsIgnoreSlice) {
            if (onIgnoreSliceCallback != null) {               
                onIgnoreSliceCallback();
            }

            return;
        }

        var sliceables = FindObjectsOfType<Sliceable>();

        if (sliceables == null) {
            return;
        }

        var list = GetCanSliceTarget(endPos);

        for (int i = 0; i < sliceables.Length; i++) {
            var sliceable = sliceables[i];
            var slicedTarget = sliceable.GetComponent<SlicedTarget>();

            try {
                if (slicedTarget && list.Contains(sliceable.GetComponent<Collider>())) {
                    if (slicedTarget.CanSlice) {
                        var mouseDirection = (endPos - _startPos).normalized;
                        var t = sliceable.transform;
                        var targetDirection = (GetScreenPos(t.position + (t.up * 10f)) - GetScreenPos(t.position)).normalized;
                        var dot = Vector3.Dot(mouseDirection, targetDirection);

                        if (Mathf.Abs(dot) < 0.5f) {
                            sliceable.infillers[0].regionForInfill.height = 0.5f;
                        }

                        TurboSlice.instance.splitByLine(sliceable.gameObject, camera, _startPos, endPos, true);
                    } else {
                        var deltaX = endPos.x - _startPos.x;
                        var deltaY = endPos.y - _startPos.y;
                        var center = (_startPos + endPos) / 2;
                        var screenPos = camera.WorldToScreenPoint(slicedTarget.transform.position);
                        Vector3 direction;

                        // True表示鼠标水平方向滑动；False表示鼠标垂直方向移动
                        if (Mathf.Abs(deltaX) > Mathf.Abs(deltaY)) {
                            direction = screenPos.y > center.y ? center + Vector3.up : center + Vector3.down;
                        } else {
                            direction = screenPos.x > center.x ? center + Vector3.right : center + Vector3.left;
                        }

                        var worldPos = camera.ScreenToWorldPoint(new Vector3(center.x, center.y, slicedTarget.transform.position.z));
                        var worldDirection = camera.ScreenToWorldPoint(direction);
                        slicedTarget.GetComponent<Rigidbody>().AddForceAtPosition(worldDirection.normalized * 10, worldPos);
                    }
                }
            } catch (System.Exception ex) {
                Debug.LogException(ex, this);
            }
        }

        _startPos = Input.mousePosition;
    }

    float _screenPosZ = -1f;

    List<Collider> GetCanSliceTarget(Vector3 endPos) {
        if (_screenPosZ < 0) {
            _screenPosZ = GetScreenPos(GameObject.Find("Cutting Board").transform.position + (Vector3.up * 0.15f)).z;
        }
        
        var sPos = GetWorldPos(new Vector3(_startPos.x, _startPos.y, _screenPosZ));
        var ePos = GetWorldPos(new Vector3(endPos.x, endPos.y, _screenPosZ));
        var center = (sPos + ePos) / 2;
        var radius = (ePos - sPos).magnitude / 2;
        var colliders = Physics.OverlapSphere(center, radius);

        return new List<Collider>(colliders);
    }

    Vector3 GetWorldPos(Vector3 screenPos) {
        if (camera == null) {
            return Vector3.zero;
        }

        return camera.ScreenToWorldPoint(screenPos);
    }

    Vector3 GetScreenPos(Vector3 worldPos) {
        if (camera == null) {
            return Vector3.zero;
        }

        return camera.WorldToScreenPoint(worldPos);
    }
}
